//
//  UIColor+Extensions.swift
//  myhub
//
//  Created by x on 2024/5/14.
//

import Foundation

extension String: XExtensionWarapper {}

// MARK: - 计算文字高度
public extension Wrapper where Base == String {
    // MARK: - 计算文字宽高
    /// 计算文字Rect
    func boundingRect(ofAttributes attributes: [NSAttributedString.Key: Any], size: CGSize) -> CGRect {
        let boundingBox = base.boundingRect(
            with: size,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: attributes,
            context: nil
        )
        return boundingBox
    }
    /// 计算文字Size
    func size(ofAttributes attributes: [NSAttributedString.Key: Any], maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
        boundingRect(ofAttributes: attributes, size: .init(width: maxWidth, height: maxHeight)).size
    }
    /// 根据文字 UIFont 计算 size
    func size(ofFont font: UIFont, maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
        let constraintRect = CGSize(width: maxWidth, height: maxHeight)
        let boundingBox = base.boundingRect(
            with: constraintRect,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: [.font: font],
            context: nil
        )
        return boundingBox.size
    }
    /// 根据文字（默认为系统字体）高度计算宽度
    func width(ofSize size: CGFloat, maxHeight: CGFloat) -> CGFloat {
        width(
            ofFont: UIFont.systemFont(ofSize: size),
            maxHeight: maxHeight
        )
    }
    /// 根据文字高度计算宽度
    func width(ofFont font: UIFont, maxHeight: CGFloat) -> CGFloat {
        size(
            ofAttributes: [NSAttributedString.Key.font: font],
            maxWidth: CGFloat(MAXFLOAT),
            maxHeight: maxHeight
        ).width
    }
    /// 根据文字（默认为系统字体）宽度计算高度
    func height(ofSize size: CGFloat, maxWidth: CGFloat) -> CGFloat {
        height(
            ofFont: UIFont.systemFont(ofSize: size),
            maxWidth: maxWidth
        )
    }
    /// 根据文字宽度计算高度
    func height(ofFont font: UIFont, maxWidth: CGFloat) -> CGFloat {
        size(
            ofAttributes: [NSAttributedString.Key.font: font],
            maxWidth: maxWidth,
            maxHeight: CGFloat(MAXFLOAT)
        ).height
    }
}

// MARK: - 
public extension Wrapper where Base == String {
    // MARK: 根据字符串换成UIColor
    func color() -> UIColor? {
        var string = ""
        if self.base.lowercased().hasPrefix("0x") {
            string =  self.base.replacingOccurrences(of: "0x", with: "")
        } else if self.base.hasPrefix("#") {
            string = self.base.replacingOccurrences(of: "#", with: "")
        } else {
            string = self.base
        }

        if string.count == 3 { // convert hex to 6 digit format if in short format
            var str = ""
            string.forEach { str.append(String(repeating: String($0), count: 2)) }
            string = str
        }

        guard let hexValue = Int(string, radix: 16) else { return nil }
        
        let red = (hexValue >> 16) & 0xff
        let green = (hexValue >> 8) & 0xff
        let blue = hexValue & 0xff
        
        return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1)
    }
    
    // MARK: 将16进制字符串转为Int
    /// 将16进制字符串转为Int
    var hexInt: Int {
        return Int(base, radix: 16) ?? 0
    }
    
    // MARK: 转成拼音
   /// 转成拼音
   /// - Parameter isLatin: true：带声调，false：不带声调，默认 false
   /// - Returns: 拼音
   func toPinyin(_ isTone: Bool = false) -> String {
       let mutableString = NSMutableString(string: self.base)
       CFStringTransform(mutableString, nil, kCFStringTransformToLatin, false)
       if !isTone {
           // 不带声调
           CFStringTransform(mutableString, nil, kCFStringTransformStripDiacritics, false)
       }
       return mutableString as String
   }
       
   // MARK: 提取首字母, "爱国" --> AG
   /// 提取首字母, "爱国" --> AG
   /// - Parameter isUpper:  true：大写首字母，false: 小写首字母，默认 true
   /// - Returns: 字符串的首字母
   func pinyinInitials(_ isUpper: Bool = true) -> String {
       let pinyin = toPinyin(false).components(separatedBy: " ")
       let initials = pinyin.compactMap { String(format: "%c", $0.cString(using:.utf8)![0]) }
       return isUpper ? initials.joined().uppercased() : initials.joined()
   }
   
   // MARK: 字符串根据某个字符进行分隔成数组
   /// 字符串根据某个字符进行分隔成数组
   /// - Parameter char: 分隔符
   /// - Returns: 分隔后的数组
   func separatedByString(with char: String) -> Array<String> {
       let arraySubstrings = (base ).components(separatedBy: char)
       let arrayStrings: [String] = arraySubstrings.compactMap { "\($0)" }
       return arrayStrings
   }
    
    // MARK: 计算字符个数（英文 = 1，数字 = 1，汉语 = 2）
    /// 计算字符个数（英文 = 1，数字 = 1，汉语 = 2）
    /// - Returns: 返回字符的个数
    func customCountOfChars() -> Int {
        var count = 0
        guard (self.base).count > 0 else { return 0 }
        for i in 0...(self.base).count - 1 {
            let c: unichar = ((self.base) as NSString).character(at: i)
            if (c >= 0x4E00) {
                count += 2
            } else {
                count += 1
            }
        }
        return count
    }
    
    // MARK: 提取出字符串中所有的URL链接
    /// 提取出字符串中所有的URL链接
    /// - Returns: URL链接数组
    func getUrls() -> [String]? {
        var urls = [String]()
        // 创建一个正则表达式对象
        guard let dataDetector = try? NSDataDetector(types:  NSTextCheckingTypes(NSTextCheckingResult.CheckingType.link.rawValue)) else {
            return nil
        }
        // 匹配字符串，返回结果集
        let res = dataDetector.matches(in: self.base , options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, (self.base ).count))
        // 取出结果
        for checkingRes in res {
            urls.append((self.base as NSString).substring(with: checkingRes.range))
        }
        return urls
    }
}

// MARK: - 字符串与其他类型(字符串转 UIViewController、AnyClass、数组、字典等)的转换
public extension Wrapper where Base == String {
    
    // MARK: 字符串转 UIViewController
    /// 字符串转 UIViewController
    /// - Returns: 对应的控制器
    @discardableResult
    func toViewController() -> UIViewController? {
        // 1.获取类
        guard let trueClass: AnyClass = self.toClass() else {
            return nil
        }
        // 2.通过类创建对象
        // 2.1、将AnyClass 转化为指定的类
        guard let vcClass = trueClass as? UIViewController.Type else {
            return nil
        }
        // 2.2、通过class创建对象
        let vc = vcClass.init()
        return vc
    }
    
    // MARK: 字符串转 AnyClass
    /// 字符串转 AnyClass
    /// - Returns: 对应的 Class
    @discardableResult
    func toClass() -> AnyClass? {
        // 1.动态获取命名空间
        let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        // 2.将字符串转换为类
        // 2.1.默认情况下命名空间就是项目的名称，但是命名空间的名称是可以更改的
        guard let Class: AnyClass = NSClassFromString(namespace.replacingOccurrences(of: " ", with: "_") + "." + base) else {
            return nil
        }
        return Class
    }
    
    // MARK: 2.3、字符串转数组
    /// 字符串转数组
    /// - Returns: 转化后的数组
    func toArray() -> Array<Any> {
        let a = Array(base)
        return a
    }
    
    // MARK: 2.4、JSON 字符串 ->  Dictionary
    /// JSON 字符串 ->  Dictionary
    /// - Returns: Dictionary
    func jsonStringToDictionary() -> Dictionary<String, Any>? {
        let jsonString = self.base
        guard let jsonData: Data = jsonString.data(using: .utf8) else { return nil }
        let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
        if dict != nil {
            return (dict as! Dictionary<String, Any>)
        }
        return nil
    }
    
    // MARK: 2.5、JSON 字符串 -> Array
    /// JSON 字符串 ->  Array
    /// - Returns: Array
    func jsonStringToArray() -> Array<Any>? {
        let jsonString = self.base
        guard let jsonData: Data = jsonString.data(using: .utf8) else { return nil }
        let array = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
        if array != nil {
            return (array as! Array<Any>)
        }
        return nil
    }
    
    /// 字符串转成 CGRect
    func toCGRect() -> CGRect? {
        // 1、判断是否为空字符串
        var content = (self.base)
        guard !content.isEmpty else {
            return nil
        }
        // 2、去除所有的空格和换行
        content = self.base.x.removeAllLineAndSapcefeed
        // 3.1、正则判断 "{{0,0},{375,812}}"
        let pattern1 = #"^\{\{\d+,\d+\},\{\d+,\d+\}\}$"#
        if content.x.predicateValue(rgex: pattern1) {
            return NSCoder.cgRect(for: self.base)
        }
        // 3.2、正则判断 "(0,20,30,40)"
        let pattern2 = #"^\((\d+),(\d+),(\d+),(\d+)\)$"#
        if content.x.predicateValue(rgex: pattern2) {
            guard let regex: NSRegularExpression = try? NSRegularExpression(pattern: #"\d+"#, options: []) else {
                return nil
            }
            let results = regex.matches(in: content, options: [], range: NSMakeRange(0, content.utf16.count))
            let numbers = results.map { match in
                String(content[Range(match.range, in: content)!])
            }
            guard numbers.count == 4 else { return nil }
            content = "{{\(numbers[0]), \(numbers[1])}, {\(numbers[2]), \(numbers[3])}}"
            return NSCoder.cgRect(for: content)
        }
        return nil
    }
    private func predicateValue(rgex: String) -> Bool {
        let checker: NSPredicate = NSPredicate(format: "SELF MATCHES %@", rgex)
        return checker.evaluate(with: base)
    }
}

// MARK: 截取、替换 字符串
public extension Wrapper where Base == String {
    var removeAllLineAndSapcefeed: String {
        // 去除所有的空格
        var resultString = base.replacingOccurrences(of: " ", with: "", options: .literal, range: nil)
        // 去除所有的换行
        resultString = resultString.replacingOccurrences(of: "\n", with: "", options: .literal, range: nil)
        return resultString
    }
    
    // MARK: 截取字符串从开始到 index
    /// 截取字符串从开始到 index
    /// - Parameter index: 截取到的位置
    /// - Returns: 截取后的字符串
    func sub(to index: Int) -> String {
        let end_Index = validIndex(original: index)
        return String(base[base.startIndex ..< end_Index])
    }
    
    // MARK: 截取字符串从index到结束
    /// 截取字符串从index到结束
    /// - Parameter index: 截取结束的位置
    /// - Returns: 截取后的字符串
    func sub(from index: Int) -> String {
        let start_index = validIndex(original: index)
        return String(base[start_index ..< base.endIndex])
    }
    
    // MARK: 获取指定位置和长度的字符串
    /// 获取指定位置和大小的字符串
    /// - Parameters:
    ///   - start: 开始位置
    ///   - length: 长度
    /// - Returns: 截取后的字符串
    func sub(start: Int, length: Int = -1) -> String {
        var len = length
        if len == -1 || (start + length) > base.count {
            len = base.count - start
        }
        let st = base.index(base.startIndex, offsetBy: start)
        let en = base.index(st, offsetBy: len)
        let range = st ..< en
        return String(base[range]) // .substring(with:range)
    }
    // MARK: 11.4、切割字符串(区间范围 前闭后开)
    /**
     CountableClosedRange：可数的闭区间，如 0...2
     CountableRange：可数的开区间，如 0..<2
     ClosedRange：不可数的闭区间，如 0.1...2.1
     Range：不可数的开居间，如 0.1..<2.1
     */
    /// 切割字符串(区间范围 前闭后开)
    /// - Parameter range: 范围
    /// - Returns: 切割后的字符串
    func slice(_ range: CountableRange<Int>) -> String {
        // 如 slice(2..<6)
        /**
         upperBound（上界）
         lowerBound（下界）
         */
        let startIndex = validIndex(original: range.lowerBound)
        let endIndex = validIndex(original: range.upperBound)
        guard startIndex < endIndex else {
            return ""
        }
        return String(base[startIndex ..< endIndex])
    }
    // MARK: 校验字符串位置是否合理，并返回String.Index
    /// 校验字符串位置是否合理，并返回String.Index
    /// - Parameter original: 位置
    /// - Returns: String.Index
    func validIndex(original: Int) -> String.Index {
        switch original {
        case ...base.startIndex.utf16Offset(in: base):
            return base.startIndex
        case base.endIndex.utf16Offset(in: base)...:
            return base.endIndex
        default:
            return base.index(base.startIndex, offsetBy: original > base.count ? base.count : original)
        }
    }
}

// MARK: - 沙盒路径的获取
/*
 - 1、Home(应用程序包)目录
 - 整个应用程序各文档所在的目录,包含了所有的资源文件和可执行文件
 - 2、Documents
 - 保存应用运行时生成的需要持久化的数据，iTunes同步设备时会备份该目录
 - 需要保存由"应用程序本身"产生的文件或者数据，例如: 游戏进度，涂鸦软件的绘图
 - 目录中的文件会被自动保存在 iCloud
 - 注意: 不要保存从网络上下载的文件，否则会无法上架!
 - 3、Library
 - 3.1、Library/Cache
 - 保存应用运行时生成的需要持久化的数据，iTunes同步设备时不备份该目录。一般存放体积大、不需要备份的非重要数据
 - 保存临时文件,"后续需要使用"，例如: 缓存的图片，离线数据（地图数据）
 - 系统不会清理 cache 目录中的文件
 - 就要求程序开发时, "必须提供 cache 目录的清理解决方案"
 - 3.2、Library/Preference
 - 保存应用的所有偏好设置，IOS的Settings应用会在该目录中查找应用的设置信息。iTunes
 - 用户偏好，使用 NSUserDefault 直接读写！
 - 如果想要数据及时写入硬盘，还需要调用一个同步方法
 - 4、tmp
 - 保存临时文件，"后续不需要使用"
 - tmp 目录中的文件，系统会自动被清空
 - 重新启动手机, tmp 目录会被清空
 - 系统磁盘空间不足时，系统也会自动清理
 - 保存应用运行时所需要的临时数据，使用完毕后再将相应的文件从该目录删除。应用没有运行，系统也可能会清除该目录下的文件，iTunes不会同步备份该目录
 */
public extension Wrapper where Base == String {
    // MARK: 获取Home的完整路径名
    /// 获取Home的完整路径名
    /// - Returns: Home的完整路径名
    static func homeDirectory() -> String {
        //获取程序的Home目录
        let homeDirectory = NSHomeDirectory()
        return homeDirectory
    }
    
    // MARK: 获取Documnets的完整路径名
    /// 获取Documnets的完整路径名
    /// - Returns: Documnets的完整路径名
    static func DocumnetsDirectory() -> String {
        //获取程序的documentPaths目录
        //方法1
        // let documentPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        // let documnetPath = documentPaths[0]
        
        //方法2
        let ducumentPath = NSHomeDirectory() + "/Documents"
        return ducumentPath
    }
        
    // MARK: 获取Library的完整路径名
    /**
     这个目录下有两个子目录：Caches 和 Preferences
     Library/Preferences目录，包含应用程序的偏好设置文件。不应该直接创建偏好设置文件，而是应该使用NSUserDefaults类来取得和设置应用程序的偏好。
     Library/Caches目录，主要存放缓存文件，iTunes不会备份此目录，此目录下文件不会再应用退出时删除
     */
    /// 获取Library的完整路径名
    /// - Returns: Library的完整路径名
    static func LibraryDirectory() -> String {
        //获取程序的documentPaths目录
        //Library目录－方法1
        // let libraryPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        // let libraryPath = libraryPaths[0]
        //
        // Library目录－方法2
        let libraryPath = NSHomeDirectory() + "/Library"
        return libraryPath
    }

    // MARK: 获取/Library/Caches的完整路径名
    /// 获取/Library/Caches的完整路径名
    /// - Returns: /Library/Caches的完整路径名
    static func CachesDirectory() -> String {
        //获取程序的/Library/Caches目录
        let cachesPath = NSHomeDirectory() + "/Library/Caches"
        return cachesPath
    }

    // MARK: 获取Library/Preferences的完整路径名
    /// 获取Library/Preferences的完整路径名
    /// - Returns: Library/Preferences的完整路径名
    static func PreferencesDirectory() -> String {
        //Library/Preferences目录－方法2
        let preferencesPath = NSHomeDirectory() + "/Library/Preferences"
        return preferencesPath
    }

    // MARK: 获取Tmp的完整路径名
    /// 获取Tmp的完整路径名，用于存放临时文件，保存应用程序再次启动过程中不需要的信息，重启后清空。
    /// - Returns: Tmp的完整路径名
    static func TmpDirectory() -> String {
        //方法1
        //let tmpDir = NSTemporaryDirectory()
        //方法2
        let tmpDir = NSHomeDirectory() + "/tmp"
        return tmpDir
    }
}
